using System;
using System.Collections;
using System.Collections.Generic;
using FrameWork;
using UnityEngine;
using FrameWork.HTN;
using Random = UnityEngine.Random;

namespace NPC.Enemy
{
     // BOSS HTN代理构建
    public class BossAgent : MonoBehaviour
    {
        /****************** 组件 *******************/
        [SerializeField] private Animator animator;
        public Animator Animator { get { return animator; } }
        private HTNPlanBuilder hTN;
        public HTNPlanBuilder GetHTN{get{return hTN;}}
        
        /****************** 世界状态 *******************/
        [Header("战斗信息")]
        [SerializeField] private float damage = 5f;                                      // 攻击伤害 用在 火球身上 - 世界状态-只读
        
        [Header("基础信息")]
        [SerializeField] private float patrolMoveSpeed;                                  // 巡逻速度 - 世界状态-只读
        [SerializeField] private float chaseMoveSpeed;                                   // 追击速度 - 世界状态-只读
        
        [Header("血量状态")]
        [SerializeField] private float healthMax = 500f;                                 // 最大血量 - 世界状态-只读
        [SerializeField] private float restoringHealth = 20f;                            // 恢复血量 - 世界状态-只读
        public float Health { get; set; }                                                // 当前血量 - 世界状态-读写
        
        [Header("检测玩家距离")]
        [SerializeField] private GameObject player;                                      // 玩家
        public float DistanceToPlayer { get; set; }                                      // 与玩家的距离 - 世界状态-读写

        [Header("攻击范围")]
        [SerializeField] private Vector2 fireballRadius = new Vector2(2, 2);             // 火球释放范围，围绕玩家
        [SerializeField] private Vector2 summonSlimeRadius = new Vector2(4, 4);          // 史莱姆释放范围，围绕玩家
        
        /****************** 非世界状态，标记信息 *******************/
        [Header("巡逻追击")]
        [SerializeField] private float chaseDistance = 8f;                               // 追击距离，小于该距离追击玩家
        [SerializeField] private float attackDistance = 4f;                              // 攻击距离，小于该距离攻击玩家
        [SerializeField] private Vector2 leftPatrolPos;                                  // 巡逻范围左边界
        [SerializeField] private Vector2 rightPatrolPos;                                 // 巡逻范围右边界
        
        [Header("技能释放系数")]
        [SerializeField] private float takeFireballAndSummonSlime = 0.8f;                // 发射火球 或 发射火球和召唤史莱姆
        [SerializeField] private float takeBerserkAttack = 0.2f;                         // 暴怒攻击
        
        /****************** 设置朝向 *******************/
        public float horizontal;
        public float vertical;

        private void Awake()
        {
            animator = GetComponent<Animator>();

            horizontal = 1;
            vertical = 1;
        }


        private void Start()
        {
            // 初始化信息
            player = GameObject.FindGameObjectWithTag("Player");                         // 查询玩家位置
            Health = healthMax;
            /************** 初始化世界状态 ***************/
            // 独写
            HTNWorld.AddState("BossHealth", () => Health, (value) => Health = (float)value);
            HTNWorld.AddState("DistanceToPlayer", () => DistanceToPlayer, value => DistanceToPlayer = (float)value);
            
            // 只读
            // 血量
            HTNWorld.AddState("BossMaxHealth", () => healthMax);
            HTNWorld.AddState("BossRestoringHealth", () => restoringHealth);
            // 战斗
            HTNWorld.AddState("BossDamage", () => damage);
            // 移动
            HTNWorld.AddState("BossPatrolMoveSpeed", () => patrolMoveSpeed);
            HTNWorld.AddState("BossChaseMoveSpeed", () => chaseMoveSpeed);

            // 构建HTN任务树
            hTN = new HTNPlanBuilder();

            hTN.CompoundTask()
                // 当BOSS与玩家距离大于巡逻距离，执行巡逻任务
                .Method(() => HTNWorld.GetWorldState<float>("DistanceToPlayer") > chaseDistance)
                .Boss_Patrol(this, leftPatrolPos, rightPatrolPos)
                .Back()
                // 当BOSS与玩家距离小于巡逻距离但大于攻击距离，执行追击任务
                .Method(() =>
                    HTNWorld.GetWorldState<float>("DistanceToPlayer") <= chaseDistance &&
                    HTNWorld.GetWorldState<float>("DistanceToPlayer") >  attackDistance)
                .Boss_Chase(this)
                .Back()
                // 当BOSS与玩家距离小于攻击距离，执行攻击任务
                .Method(() => HTNWorld.GetWorldState<float>("DistanceToPlayer") <= attackDistance)
                // 攻击任务是一个复合任务
                .CompoundTask()
                // 当BOSS血量大于80%，发射火球
                .Method(() =>
                    HTNWorld.GetWorldState<float>("BossHealth") / HTNWorld.GetWorldState<float>("BossMaxHealth") > takeFireballAndSummonSlime)
                .Boss_Fireball(this)
                .Back()
                // 当BOSS血量在20%到80%之间，发射火球并召唤史莱姆
                .Method(() =>
                    HTNWorld.GetWorldState<float>("BossHealth") / HTNWorld.GetWorldState<float>("BossMaxHealth") >
                    takeBerserkAttack &&
                    HTNWorld.GetWorldState<float>("BossHealth") / HTNWorld.GetWorldState<float>("BossMaxHealth") <=
                    takeFireballAndSummonSlime)
                .Boss_Fireball(this)
                .Boss_SummonSlime(this)
                .Back()
                // 当BOSS血量小于20%，发射火球并召唤史莱姆并进入暴怒状态
                .Method(() =>
                    HTNWorld.GetWorldState<float>("BossHealth") / HTNWorld.GetWorldState<float>("BossMaxHealth") <=
                    takeBerserkAttack)
                .Boss_Fireball(this)
                .Boss_SummonSlime(this)
                .Boss_BerserkState(this)
                .End();
        }

        #region WithOut Use

        public void SetUpdate()
        {
            // 更新玩家与Boss距离
            HTNWorld.UpdateState("DistanceToPlayer", Mathf.Abs(Vector2.Distance(player.transform.position, transform.position)));
            // 每帧运行任务
            hTN.RunPlan();
        }

        public void TakeAnimation(string name)
        {
            animator.Play(name);
        }

        public void SetFace()
        {
            if (player.transform.position.y > transform.position.y)
            {
                vertical = 0.5f;
            }
            else if (player.transform.position.y < transform.position.y)
            {
                vertical = 1f;
            }
            else
            {
                vertical = 0f;
            }

            if (player.transform.position.x >= transform.position.x)
            {
                horizontal = 1f;
            }
            else
            {
                horizontal = -1f;
            }
            
            Face(horizontal, vertical);
        }

        public void Face(float horizontal, float vertical)
        {
            transform.localScale = new Vector3(horizontal, 1, 1);
            
            animator.SetFloat("Face", vertical);
        }

        public void ChasePlayer()
        {
            transform.position = Vector3.MoveTowards(transform.position, player.transform.position,
                HTNWorld.GetWorldState<float>("BossChaseMoveSpeed") * Time.deltaTime);
        }

        public void TakeFireball()
        {
            // EventSystem.Instance.EventTrigger(EventName.EVENT_AUDIO_SFX_PLAY, "BossAttack");
            // 玩家身边小范围内随机生成火球
            Vector2 target = new Vector2(Random.Range(player.transform.position.x - fireballRadius.x, player.transform.position.x + fireballRadius.x),
                Random.Range(player.transform.position.y - fireballRadius.y, player.transform.position.y + fireballRadius.y));

            GameObject obj = ObjectPool.Instance.Spawn("Fireball");
            obj.GetComponent<IBullet>().SetDamage(damage);
            obj.transform.position = target;
            obj.transform.SetParent(this.transform);
        }

        public void TakeSlime(int value)
        {
            for (int i = 0; i < value; i++)
            {
                // BOSS周边区域随机位置生成随机数量的史莱姆
                Vector2 target = new Vector2(Random.Range(player.transform.position.x - summonSlimeRadius.x, player.transform.position.x + summonSlimeRadius.x),
                    Random.Range(player.transform.position.y - summonSlimeRadius.y, player.transform.position.y + summonSlimeRadius.y));

                GameObject obj = ObjectPool.Instance.Spawn("Slime");
                obj.transform.position = target;
                obj.transform.SetParent(this.transform);
            }
        }
    }

    #endregion
}